#include <algorithm>

#include <utils/cconfig.h>

/** Default Constructor
 */

CConfig::CConfig()
{

}

/** Default Destructor
 */

CConfig::~CConfig()
{

}

/** Default Copy Constructor
 */

CConfig::CConfig(const CConfig& other)
{

}

/** Default Assignment Operator
 */

CConfig& CConfig::operator=(const CConfig& rhs)
{
    if (this == &rhs)
    {
        return *this;
    }

    return *this;
}

/** Opens the passed filename as a configuration file.
 *  \return Returns true if the read was successful, else it
 *  returns false;
 */

bool CConfig::Read()
{
    // We could either use PhysFS or the C++ standard for reading.
    // For simplicity, I chose the C++ standard.

    std::fstream in;
    in.open(m_FileName.c_str(), std::fstream::in);

    if (in.fail())
    {
        // Failed to open the file. Probably means it doesn't exist.
        return false;
    }
    else
    {
        // Successfully opened the file.

        std::string line;

        while (!in.eof())
        {
            std::getline(in, line);

            // Ignore blank lines.

            if (line.empty())
            {
                continue;
            }

            // Remove newlines and partial newlines.

            line.erase(remove(line.begin(), line.end(), '\r'), line.end());
            line.erase(remove(line.begin(), line.end(), '\n'), line.end());

            std::string::size_type split = line.find("=");

            if (split == std::string::npos)
            {
                continue;
            }

            std::string::size_type keyStart = line.find_first_not_of(" ");
            std::string::size_type keyEnd = line.find(" ", keyStart);
            std::string::size_type valueStart = line.find_first_not_of(" ", split + 1);
            std::string::size_type valueEnd = line.size();

            // Convert all the keys to lowercase to avoid any case issues.

            std::transform(line.begin(), line.begin() + split, line.begin(), (int(*)(int)) std::tolower);

            if (valueStart != std::string::npos)
            {
                // Save the key/value into a map.
                m_Config[line.substr(keyStart, keyEnd - keyStart)] = line.substr(valueStart, valueEnd - valueStart);
            }
        }

        in.close();
    }

    return true;
}

/** Fetches the value assigned to the passed key. This assumes the
 *  value is an integer. Note that a file must have been read before
 *  calling this function with Read().
 *  \param Defines the key to use when searching through the map.
 *  \param If the key is not found, or there is no value for the key
 *  the function should return this value as the default value.
 *  \return Returns the value assigned to the passed key parameter as
 *  an integer.
 */

int CConfig::GetInt(const std::string& key, int def)
{
    if (m_Config.find(key) == m_Config.end())
    {
        return def;
    }
    else
    {
        return atoi(m_Config[key].c_str());
    }
}

/** Fetches the value assigned to the passed key. This assumes the
 *  value is a string. Note that a file must have been read before
 *  calling this function with Read().
 *  \param Defines the key to use when searching through the map.
 *  \param If the key is not found, or there is no value for the key
 *  the function should return this value as the default value.
 *  \return Returns the value assigned to the passed key parameter as
 *  a string.
 */

std::string CConfig::GetString(const std::string& key, const std::string& def)
{
    if (m_Config.find(key) == m_Config.end())
    {
        return def;
    }
    else
    {
        return m_Config[key];
    }
}

/** Writes a key with the corresponding value through the output stream.
 *  \param Name of the key to save as.
 *  \param Value to be set with the key
 */

void CConfig::WriteValue(const std::string& key, int value)
{
    m_Write << key << " = " << value << std::endl;
}

/** Writes a key with the corresponding value through the output stream.
 *  \param Name of the key to save as.
 *  \param Value to be set with the key
 */

void CConfig::WriteValue(const std::string& key, const std::string& value)
{
    m_Write << key << " = " << value << std::endl;
}

/** Starts an output file stream. This needs to be called before WriteValue().
 *  \return Returns true if the file was successfully opened, else it returns
 *  false.
 */

bool CConfig::StartWrite()
{
    m_Write.open(m_FileName.c_str(), std::fstream::out | std::fstream::trunc);

    if (m_Write.fail())
    {
        // Failed to open the file. Probably means it doesn't exist.
        return false;
    }
    else
    {
        return true;
    }
}

/** Closes the output file stream. This needs to be called after you are done
 *  with the WriteValue() calls.
 */

void CConfig::EndWrite()
{
    m_Write.close();
}
